package com.jeaven.classloader;

import com.jeaven.VirtualMachine;
import com.jeaven.classfile.ClassFile;
import com.jeaven.classfile.attribute.BootstrapMethods;
import com.jeaven.classfile.attribute.Code;
import com.jeaven.classfile.fields.Field;
import com.jeaven.classfile.interfaces.Interface;
import com.jeaven.classfile.methods.Method;
import com.jeaven.classpath.ClassPath;
import com.jeaven.rtda.Slot;
import com.jeaven.rtda.heap.KClass;
import com.jeaven.rtda.heap.KField;
import com.jeaven.rtda.heap.KMethod;
import com.jeaven.utils.Utils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

// 应用程序类加载器
public class ApplicationClassLoader implements ClassLoader {
    // TO-DO
    // 这个类用来实现加载 classfile 分配在 JVM 的 rtda 中，静态的类模板是 KClass
    // 暂时简单实现，没有实现双亲委派机制

    public ApplicationClassLoader() {
        super();
    }

    public void loadClass(String className) throws IOException {
        ClassFile classFile = ClassPath.findClass1(className);
        KClass kClass = doLoadClass(className, classFile);
        className = className.replace(".", "/");
        registerClass(className, kClass);
    }


    public KClass doLoadClass(ClassFile classFile) {
        return doLoadClass(null, classFile);
    }

    // 将 classfile 加载位 KClass 类型的内存数据
    public KClass doLoadClass(String name, ClassFile classFile) {
        List<KMethod> methods = new ArrayList<>();
        for (Method method : classFile.methods.methods) {
            // 将 classfile 中的 method 转换为 kmethod
            Code code = method.getCode();
            if (code == null) {
                methods.add(new KMethod(method.accessFlags, method.name, method.descriptor.descriptor, 0, 0,
                        null, null, method.getLineNumber()));
            } else {
                methods.add(new KMethod(method.accessFlags, method.name, method.descriptor.descriptor,
                        code.maxStacks, code.maxLocals, code.getInstructions(), code.exceptionTable,
                        method.getLineNumber()));
            }
        }

        List<KField> fields = new ArrayList<>();
        for (Field field : classFile.fields.fields) {
            // 将 classfile 中的 field 转换为 kfield
            fields.add(new KField(field.accessFlags, field.name, field.descriptor.descriptor));
        }

        // field interfaceInit 分配存储空间
        for (KField it : fields) {
            switch (it.descriptor) {
                case "Z":
                case "C":
                case "B":
                case "S":
                case "I":
                    it.val = new Slot[]{new Slot(0, Slot.INT)};
                    break;
                case "F":
                    it.val = new Slot[]{new Slot(0, Slot.FLOAT)};
                    break;
                case "D":
                    it.val = new Slot[]{new Slot(0, Slot.DOUBLE_HIGH), new Slot(0, Slot.DOUBLE_LOW)};
                    break;
                case "J":
                    it.val = new Slot[]{new Slot(0, Slot.LONG_HIGH), new Slot(0, Slot.LONG_LOW)};
                    break;
                default:
                    it.val = new Slot[]{new Slot(null)};
                    break;
            }
        }

        int scIdx = classFile.superClass;
        String superClassName = null;
        if (scIdx != 0) {
            superClassName = Utils.getClassName(classFile.cpInfo, scIdx);
        }

        List<String> interfaceNames = new ArrayList<>();
        if (classFile.interfaces.interfaces.length != 0) {
            for (Interface anInterface : classFile.interfaces.interfaces) {
                interfaceNames.add(anInterface.getName());
            }
        }

        BootstrapMethods bootstrapMethods = classFile.getBootstrapMethods();

        return new KClass(classFile.accessFlags, name, superClassName, interfaceNames, methods, fields,
                bootstrapMethods, classFile.cpInfo, this, classFile);
    }

    // 将类的模板注册到 JVM 堆内存中的方法区
    public void registerClass(String className, KClass kClass) {
        VirtualMachine.heap.registerClass(className, kClass);
    }
}
